package simulator;

import java.util.*;
import java.io.*;
/**
 * @deprecated 
 * Never worked, replaced by the Visual Maze Builder tool
 * This class generates mazes
 * ('maze' in this case refers to an instance of Environment containing walls
 * configured according to the rules of IARoC)
 * @author morris
 *
 */

public class MazeGenerator {
	public static final int wallwidth = 1; 
	public static int cellsX;
	public static int cellsY;
	public static int boxW;
	
	public static BufferedWriter b; 
	
	 public static boolean startDone; //already positioned start?
	 public static int startX;
	 public static int startY;
	 
	 public static boolean[][] horizwalls;
	 public static boolean[][] vertwalls;
	 public static boolean[][] visited;	 

	 public static final int north = 0;
	 public static final int east = 1;
	 public static final int south = 2;
	 public static final int west = 3;
	
	/**
	 * generates a maze with specified width and height
	 * hopefully width and height are both multiples of wallwidth, otherwise difficulty ensues
	 * implements a depth-first recursive backtracking algorithm
	 * (see http://en.wikipedia.org/wiki/Maze_generation_algorithm)
	 * @param width desired width of maze
	 * @param height desired height of maze
	 * @return a randomly generated maze of width and height
	 */
	 public static void main (String[] args) throws IOException
	 {
	 b = new BufferedWriter(new FileWriter("viewTesting.txt"));
	b.write("MAKING MAZE");
	 
	 	startDone = false; // the start has not been place
	 	cellsX = 6; //width in boxess
	 	cellsY= 4; // height in boxes
	 	boxW = 40; // width/height of 1 box in units
	 	 	
	 	width = cellsX * boxW; // width of maze in units
	 	height = cellsY * boxW; //height of maze in units

		generateMaze2(width, height); 
		newSearch(); // place start
		newSearch();// place beacon
		
		maze.add(new Wall(0, 0, width, wallwidth)); // top wall of maze
		System.out.println("Wall, 0, 0, " + width + ", " + wallwidth); 
		
		maze.add(new Wall(0, 0, wallwidth, height)); //left side
		System.out.println("Wall, 0, 0, " + wallwidth + ", " + height);
		
		maze.add(new Wall(0, height, width, wallwidth)); //bottom
		System.out.println("Wall, 0, " + height + ", " + width + ", " + wallwidth);
		
		maze.add(new Wall(width, 0, wallwidth, height)); //right side
		System.out.println("Wall, " + width + ", 0, " + wallwidth + ", " + height);
	 
	 	
	 	b.close();
	 	
	 }
	 	 
public static boolean[] sidecheck(int x, int y)throws IOException{ 
//checks which sides of cell don't have walls
	 	int possiblepaths = 0;
	 	boolean[] directions = new boolean[4]; //N, E, S, W
	if(x < 0 || y < 0)// something bad happened
		{ b.write("\n SOMETHING BAD HAPPENED IN SIDE CHECK OF " + x + ", " + y);
		return directions;
		}
		if(x > 0 && vertwalls[x][y]){// can go left from here
		possiblepaths++;
		directions[west] = true;
		}if(x < cellsX - 1 && vertwalls[x + 1][y]){// can go right from here
		possiblepaths++;
		directions[east] = true;
		}if(y > 0 && horizwalls[x][y]){// can go up from here
		possiblepaths++;
		directions[north] = true;
		}if(y < cellsY - 1 && horizwalls[x][y + 1]){// can go down from here
		possiblepaths++;
		directions[south] = true;
		}
	return directions;
	 }
public static int height;
public static int width;
public static void newSearch()throws IOException{
		int X = (int)(Math.random() * cellsX);
		int Y = (int)(Math.random() * cellsY);
	
		searchFrom(X, Y, X, Y);
	}
public static void searchFrom(int x, int y, int lastX, int lastY)throws IOException{ // finds places for beacon and start
		boolean[] directions = sidecheck(x, y);
		if(x != lastX){
			int xOf = x - lastX;
			if(xOf == -1){
			directions[east] = false;
			}else directions[west] = false;
		}else if(y != lastY){
			int yOf = y - lastY;
			if(yOf == -1){
			directions[south] = false;
			}else directions[north] = false;
		}
	
	boolean cancontinue;
	cancontinue = false;
	for(int i = 0; i < 4; i++){
	  if(directions[i])
	    cancontinue = true;
	}
	
	if(! cancontinue){// dead end found
		if(! startDone){
			startDone = true;
			startX = x;
			startY = y;
			
			
			System.out.println("Start, " + (x +.5) * boxW + ", " + (y+ .5) * boxW);
			maze.setStart((x + .5) * boxW, (y+.5)* boxW, 0);
		}else if(x != startX && y != startY){
			System.out.println("Beacon, " + (x + .5) * boxW + ", " + (y + .5) * boxW);
			maze.add(new Beacon((x + .5) * boxW, (y + .5) * boxW));
		}else{// beacon and start are same place, relocate beacon
			newSearch();	
		}
	
	
	
	}else{//keep going to find dead end
		int i = (int)(4 * Math.random());
	
	while(! directions[i]){
		i = (int)(4 * Math.random());
	}
	
	int xOf;
	int yOf;
	if(i == 0){
		xOf = 0;
		yOf = -1;
	}else if(i == 1){
		xOf = 1; 
		yOf = 0;
	}else if(i == 2){
		xOf = 0;
		yOf = -1;
	}else{
		xOf = -1;
		yOf = 0;
	}
	
	int newX = x + xOf;
	int newY = y + yOf;
	searchFrom(newX, newY, x, y);
	
	}
	 }
	
	 public static Environment maze;

	public static Environment generateMaze2(int width, int height)throws IOException{
	maze = new Environment();
	 visited = new boolean[cellsX][cellsY]; // has a boolean for each cell
	 horizwalls = new boolean[cellsX][cellsY + 1]; // should a particular cell NOT have a wall?
	vertwalls = new boolean[cellsX + 1][cellsY]; // note: defaults to false
	int[] crCell = new int[2];
		crCell[0] = (int) (Math.random() * cellsX);
		crCell[1] = 0;
	
	recurseGen(0,0);//edit starting pt
	
	addWalls();
	return maze;
	}
public static void recurseGen(int X, int Y) throws IOException{
	
	b.write("\n RECURSEGEN (" + X + ", " + Y + ")");
	visited[X][Y] = true;
	ArrayList<int[]> neighbors = getNeighbors(X, Y);
	
	while(neighbors.size() > 0){
	int index = (int)(Math.random() * neighbors.size());
	int[]  n = neighbors.get(index);
	neighbors.remove(index);
		b.write("\n       neighbor (" + n[0] + ", " + n[1] + ")");
	if(! visited[n[0]][n[1]]){
	removeWall(X, Y, n[0], n[1]); //take out wall between 2 cells
		recurseGen(n[0], n[1]);
		
	}
	}
	}
public static void removeWall(int xa, int ya, int xb, int yb)throws IOException{
	if(xa > xb){
	// take out wall west of square a
	b.write("\n REMOVING WALL WEST OF (" + xa + ", " + ya + ") \n" 
	);
	vertwalls[xa][ya] = true;
	}else if(xa < xb){
	// take out wall west of square b
	b.write("\n REMOVING WALL WEST OF (" + xb + ", " + yb + ")\n"  
	);
	vertwalls[xb][yb] = true;
	}else if(ya<yb){
	//take out wall south of square a
	int t = ya + 1;
	b.write("\n REMOVING WALL SOUTH OF (" + xa + ", " + ya + ")\n" 
	);
	horizwalls[xa][ya + 1] = true;
	}
	else if(ya > yb){
	int t = yb + 1;
	b.write("\n REMOVING WALL SOUTH OF (" + xb + ", " + yb + ")\n" 
	 );
	// take out wall south of square b
	horizwalls[xb][yb + 1] = true;
	}
	else
	b.write("NO WALL TO REMOVE");
	}
public static Environment generateMaze(int width, int height) throws IOException{
				//BufferedWriter b = new BufferedWriter(new FileWriter("testmaze.txt"));
		
		maze = new Environment();
		
		
		visited = new boolean[cellsX][cellsY]; // has a boolean for each cell
		horizwalls = new boolean[cellsX][cellsY + 1]; // should a particular cell NOT have a wall?
		vertwalls = new boolean[cellsX + 1][cellsY]; // note: defaults to false
		
		int[] coords = {0, 0};  //{(int)(Math.random() * cellsX), 0}; // coordinates to start at
		Stack<int[]> cellstack = new Stack<int[]>();
		cellstack.push(coords);
		recurse(cellstack, cellsX, cellsY);
		return maze;
		}
public static void addWalls(){
		// add horizontal walls
		for(int i = 0; i < cellsX; i++){
			for(int j = 0; j < cellsY + 1; j++){
			if(!horizwalls[i][j]){
			maze.add(new Wall(i * boxW, j  * boxW, boxW, wallwidth));
			System.out.println("Wall, " + i * boxW + ", " + j * boxW + ", " + boxW + ", " + wallwidth);
			}
			}
		}
			
		//add vertical walls
		for(int i = 0; i < cellsY; i++){
		for(int j = 0; j < cellsX + 1; j++){
			if(! vertwalls[j][i]){
			maze.add(new Wall(j * boxW, i * boxW, wallwidth, boxW));
			System.out.println("Wall, " + j * boxW + ", " + i * boxW + ", " + wallwidth + ", " + boxW);
			}
		
		}
		}
	}
public static ArrayList<int[]> getNeighbors(int x, int y){
	int[] cell = new int[2];
	cell[0] = x;
	cell[1] = y;
	return getNeighbors(cell);
	
	}
	
private static ArrayList<int[]> getNeighbors(int[] curcell) {
		ArrayList<int[]> neighbors = new ArrayList<int[]>();
		for(int i = -1; i <= 1; i++)
			for(int j = -1; j <= 1; j++) // visit all neighbors
				if((i == 0) ^ (j == 0)) {
					int x = curcell[0] + i;
					if(x >= 0 && x < cellsX) { // check to see if neighbor exists
						int y = curcell[1] + j;
						if(y >= 0 && y < cellsY
								&& !visited[x][y]) { // ...and hasn't been visited
							int[] coords = {x, y};
							neighbors.add(coords); // if so, add to ArrayList neighbors
						}
					}
				}
		return neighbors;
	}
	
private static void recurse(Stack<int[]> cellstack, int cellsX, int cellsY) {
		if(!cellstack.isEmpty()) {
			int[] curcell = cellstack.peek(); //get the current cell
			visited[curcell[0]][curcell[1]] = true; //it's been visited now
			
			ArrayList<int[]> neighbors = getNeighbors(curcell);
			
			if(!neighbors.isEmpty()) {
				while(!neighbors.isEmpty()) { //time for recursion!
					//do it to neighbors till none haven't been visited
					int[] newcell = neighbors.remove((int)(Math.random() * neighbors.size()));
					
					if(visited[newcell[0]][newcell[1]]){}
					else{
					cellstack.add(newcell);
					int xof = curcell[0] - newcell[0]; //x + y offsets
					int yof = curcell[1] - newcell[1];
					
					
					//remove wall between
					if(xof == -1){//wall W of newcell
					vertwalls[newcell[0]][newcell[1]] = true;
					}
					else if(xof == 1){// wall E of newcell
					vertwalls[newcell[0] + 1][newcell[1]] = true;
					}
					else if(yof == -1){// wall S of newcell
					horizwalls[newcell[0]][newcell[1] + 1] = true;
					}
					else if(yof == 1){// wall N of newcell
					horizwalls[newcell[0]][newcell[1]] = true;
					}
					
					//if(xof != 0) { //remove the wall bw/ the two cells
					//	vertwalls[curcell[0]][curcell[1]] = true;
					//} else{
					//	horizwalls[curcell[0]][curcell[1]] = true;
					//}
					recurse(cellstack, cellsX, cellsY);
					  }
				}
			} else {
				cellstack.pop();
			}
		}
	}
}
